package server

import (
	"bytes"
	"encoding/json"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"
)

func StartMDDataSync() {
	for {
		Sync()
		time.Sleep(time.Minute * 5)
	}
}
func Sync() {
	//fmt.Println("start sync")
	db, err := Mongo()
	if err != nil {
		fmt.Println(err)
		return
	}
	filter := bson.M{}
	opts := options.FindOptions{
		Sort: bson.M{
			"updateTime": -1,
		},
	}
	docs := bson.A{}
	db.FindMany(CgsMDWorksheetInfoCollectionName, filter, &docs, &opts)
	//fmt.Printf("synced %d\n", len(docs))
	for _, v := range docs {
		v1 := v.(bson.D).Map()
		appKey := v1["appKey"].(string)
		sign := v1["sign"].(string)
		baseUrl := v1["baseUrl"].(string)
		worksheetId := v1["worksheetId"].(string)
		appId := v1["appId"].(string)
		viewId := v1["viewId"].(string)
		cgsWsId := v1["cgsWsId"].(primitive.ObjectID).Hex()
		controls := v1["controls"].(bson.A)
		mdWsId := v1["id"].(primitive.ObjectID)
		var synced = 0
		if v1["total"] != nil {
			synced, _ = strconv.Atoi(v1["total"].(string))
		}
		var mdUtime string
		if v1["mdUtime"] != nil {
			mdUtime = v1["mdUtime"].(string)
		}
		var filterType = 14
		if mdUtime == "" {
			mdUtime = time.Now().Format("2006-01-02 15:04:05")
			filterType = 16

		}
		// 明道云只支持按天粒度查询utime 所以当天更新的数据需要重复查询和更新
		//14 >=  16 <=
		var mdFilters = []map[string]interface{}{{"controlId": "utime", "dataType": 16, "spliceType": 1, "filterType": filterType, "value": mdUtime}}
		var lastTime = time.Now().Format("2006-01-02 15:04:05")

		params := map[string]interface{}{"filters": mdFilters, "appKey": appKey, "sign": sign, "workSheetID": worksheetId, "appId": appId, "viewId": viewId, "isAsc": "true", "sortId": "_id"}
		s := listMDRows(baseUrl, params, "1", "1") //先查询第一条数据，获取记录条数 total
		var total = s.Data.Total
		//if total-synced == 0 {
		//	return
		//}
		synced = 0
		for _, v := range CalcPage(synced, total) { //根据 synced（已经同步条数）  和 total（总条数）  生成页码list
			rows := listMDRows(baseUrl, params, strconv.Itoa(v.Page), strconv.Itoa(v.Size))
			insertCGSRows(controls, rows, cgsWsId)
		}
		//Update MDWorkSheet   更新total记录数（已经同步到cgs的记录数)
		mid, _ := primitive.ObjectIDFromHex(mdWsId.Hex())
		filter := bson.M{
			"id": mid,
		}
		set := bson.M{
			"updateTime": time.Now().In(CstZone),
			//"total":strconv.Itoa(total),
		}
		if total != 0 {
			set["mdUtime"] = lastTime
		}

		update := bson.M{
			"$set": set,
		}
		db.UpdateOne(CgsMDWorksheetInfoCollectionName, filter, update)

	}

}

func insertCGSRows(controls bson.A, rows MDRows, cgsWsId string) {
	collectionName := "ws" + cgsWsId
	db, err := Mongo()
	if err != nil {
		fmt.Println(err)
		return
	}
	for _, r := range rows.Data.Rows {
		var mdRowId = r["rowid"]
		filter := bson.M{
			"mdRowId": mdRowId,
		}
		wsDoc := bson.M{}
		find, _ := db.FindOne(collectionName, filter, &wsDoc)
		for _, c := range controls {
			c1 := c.(bson.D).Map()
			controlId := c1["controlId"].(string)
			key := controlId
			alias := c1["alias"].(string)
			if alias != "" {
				key = alias
			}
			v := r[key]
			wsDoc[controlId] = v
		}
		wsDoc["mdRowId"] = r["rowid"]
		wsDoc["mdUtime"] = r["utime"]
		wsDoc["utime"] = time.Now().Format("2006-01-02 15:04:05")
		if !find {
			wsDoc["rowId"] = primitive.NewObjectID().Hex()
			db.InsertOne(collectionName, wsDoc)
		} else {
			set := wsDoc
			update := bson.M{
				"$set": set,
			}
			db.UpdateOne(collectionName, filter, update)
		}
		//

	}

}

func listMDRows(baseUrl string, params map[string]interface{}, pageIndex string, pageSize string) MDRows {
	params["pageIndex"] = pageIndex
	params["pageSize"] = pageSize
	url := baseUrl + "/v2/open/worksheet/getFilterRows"
	jsonParams, _ := json.Marshal(params)
	resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonParams))
	var s MDRows
	if err != nil {
		fmt.Println(err)
		return s
	}
	body, _ := ioutil.ReadAll(resp.Body)

	json.Unmarshal(body, &s)
	return s
}

func CalcPage(synced, total int) []Pageable {
	var pages []Pageable
	f1 := synced % 10
	syncedPage := synced / 10
	lastPage := total/10 + 1 //total may before or after lastPage
	if f1 == 0 {
		for i := syncedPage + 1; i < lastPage; i++ {
			p1 := Pageable{
				Page: i,
				Size: 10,
			}
			pages = append(pages, p1)
		}

		for j := (lastPage-1)*10 + 1; j <= total; j++ {
			pj := Pageable{
				Page: j,
				Size: 1,
			}
			pages = append(pages, pj)
		}
	} else {
		nextPage := syncedPage + 1
		if nextPage*10 >= total { //synced+1 ~ total
			for x := synced + 1; x <= total; x++ {
				px := Pageable{
					Page: x,
					Size: 1,
				}
				pages = append(pages, px)
			}
		} else {
			//synced+1 ~ nexpage*10
			for y := synced + 1; y <= nextPage*10; y++ {
				py := Pageable{
					Page: y,
					Size: 1,
				}
				pages = append(pages, py)
			}
			//nexpage~lastpage

			for z := nextPage + 1; z < lastPage; z++ {
				pz := Pageable{
					Page: z,
					Size: 10,
				}
				pages = append(pages, pz)
			}
			//lastPage~total
			for o := (lastPage-1)*10 + 1; o <= total; o++ {
				po := Pageable{
					Page: o,
					Size: 1,
				}
				pages = append(pages, po)
			}

		}

	}
	return pages

}

type Pageable struct {
	Page int
	Size int
}

type MDRows struct {
	Data MDRowData `json:"data"`
}
type MDRowData struct {
	Total int      `json:"total"`
	Rows  []bson.M `json:"rows"`
}
